use proc_macro::TokenStream;
use quote::quote;
use syn::{parenthesized};
use syn::spanned::Spanned;

#[proc_macro_derive(Builder, attributes(builder))]
pub fn derive(input: TokenStream) -> TokenStream {
    let st2 = syn::parse_macro_input!(input as syn::DeriveInput);
    match impl_builder(&st2) {
        Ok(generated) => generated.into(),
        Err(err) => err.into_compile_error().into(),
    }
}

/// 获取结构体的所有字段
fn get_struct_fields(st: &syn::DeriveInput) -> syn::Result<Vec<&syn::Field>> {
    if let syn::Data::Struct(data_struct) = &st.data {
        Ok(data_struct.fields.iter().collect::<Vec<_>>())
    } else {
        Err(syn::Error::new_spanned(st, "仅仅支持结构体"))
    }
}

/// 获取Option字段的内部类型
fn get_optional_field_inner_type(field: &syn::Field) -> Option<&syn::Type> {
    get_generic_inner_type(field, "Option")
}

/// 获取Vec字段的内部类型
fn get_vec_field_inner_type(field: &syn::Field) -> Option<&syn::Type> {
    get_generic_inner_type(field, "Vec")
}

/// 获取字段的内部类型
fn get_generic_inner_type<'a>(field: &'a syn::Field, outer_type: &str) -> Option<&'a syn::Type> {
    if let syn::Type::Path(type_path) = &field.ty {
        let path_segments = type_path.path.segments.last()?;
        if path_segments.ident != outer_type {
            return None;
        }

        let path_segments_args = &path_segments.arguments;
        if let syn::PathArguments::AngleBracketed(arguments) = path_segments_args {
            let args = arguments.args.first()?;
            if let syn::GenericArgument::Type(t) = args {
                return Some(t);
            }
        }
    }
    None
}


/// 获取builder属性
fn get_field_customer_attr_builder(field: &syn::Field) -> syn::Result<Option<syn::Ident>> {
    get_field_customer_attr_ident(field, "builder")
}
fn get_field_customer_attr_ident(field: &syn::Field,attr_name:&str) -> syn::Result<Option<syn::Ident>> {
    let attrs = &field.attrs;
    for attr in attrs {
        if attr.path().is_ident(&attr_name) {
            let meta_name_value = attr.parse_args::<syn::MetaNameValue>()?;
            if meta_name_value.path.is_ident("each") {
                if let syn::Expr::Lit(lit) = &meta_name_value.value {
                    if let syn::Lit::Str(lit_int) = &lit.lit {
                        return Ok(Some(syn::Ident::new(&lit_int.value(), attr.span())));
                    }
                }
            }else {
                return Err(syn::Error::new_spanned(&attr.meta, "expected `builder(each = \"...\")`"));
            }
        }
    }
    Ok(None)
}

fn generate_builder_function(
    fields: &Vec<&syn::Field>,
) -> syn::Result<Vec<proc_macro2::TokenStream>> {
    let mut token_vec = Vec::new();
    for field in fields {
        let ident = &field.ident;
        if get_vec_field_inner_type(field).is_some() {
            token_vec.push(quote! {
                #ident: std::vec::Vec::new()
            });
        } else {
            token_vec.push(quote! {
                #ident: std::option::Option::None
            });
        }
    }
    Ok(token_vec)
}

// 生成builder结构体的字段
fn generate_builder_struct_field(
    fields: &Vec<&syn::Field>,
) -> syn::Result<Vec<proc_macro2::TokenStream>> {
    let token = fields
        .iter()
        .map(|field| {
            let ident = &field.ident;
            let type_ = &field.ty;
            if get_vec_field_inner_type(field).is_none() && get_optional_field_inner_type(field).is_none() {
                quote! {
                    #ident: std::option::Option<#type_>
                }
            }else {
                quote! {
                    #ident:#type_
                }
            }
        })
        .collect::<Vec<_>>();
    Ok(token)
}

/// 生成builder的setter函数
fn generate_builder_setter_function(
    fields: &Vec<&syn::Field>,
) -> syn::Result<proc_macro2::TokenStream> {
    let mut setter_functions_token = proc_macro2::TokenStream::new();
    for field in fields {
        let ident = &field.ident;
        let ty = &field.ty;
        if let Some(option_inner_type) = get_optional_field_inner_type(field) {
            setter_functions_token.extend(quote! {
                fn #ident(&mut self,#ident:#option_inner_type) -> &mut Self{
                    self.#ident = std::option::Option::Some(#ident);
                    self
                }
            });
        } else if let Some(vec_inner_type) = get_vec_field_inner_type(field) {
            setter_functions_token.extend(quote! {
                fn #ident(&mut self,#ident:#ty) -> &mut Self{
                    self.#ident = #ident;
                    self
                }
            });
            if let Some(customer_attr_builder) =  get_field_customer_attr_builder(field)? {
                if ident.as_ref().unwrap() != &customer_attr_builder {
                    setter_functions_token.extend(quote! {
                        fn #customer_attr_builder(&mut self,#customer_attr_builder:#vec_inner_type) -> &mut Self{
                             self.#ident.push(#customer_attr_builder);
                             self
                         }
                    })
                }
            }
        } else {
            setter_functions_token.extend(quote! {
                    fn #ident(&mut self,#ident:#ty) -> &mut Self{
                        self.#ident = std::option::Option::Some(#ident);
                        self
                    }
            })
        }
    }

    Ok(setter_functions_token)
}

/// 生成builder的build函数
fn generate_builder_build_function(
    struct_ident: &syn::Ident,
    fields: &Vec<&syn::Field>,
) -> syn::Result<proc_macro2::TokenStream> {
    let mut condition_token_vec = Vec::new();
    let mut new_token_vec = Vec::new();
    for field in fields {
        let ident = &field.ident;
        if get_optional_field_inner_type(field).is_some() {
            new_token_vec.push(quote! {
                #ident: self.#ident.clone()
            })
        } else if get_vec_field_inner_type(field).is_some() {
            new_token_vec.push(quote! {
                #ident: self.#ident.clone()
            })
        } else {
            condition_token_vec.push(quote! {
                if self.#ident.is_none(){
                    let err = format!("{} field missing", stringify!(#ident));
                    return std::result::Result::Err(err.into());
                }
            });
            new_token_vec.push(quote! {
                #ident: self.#ident.clone().unwrap()
            })
        }

        // match get_optional_field_inner_type(&field) {
        //     Some(_) => {
        //         // 是Option字段，那么我们就直接返回改字段的拷贝
        //         new_token_vec.push(quote! {
        //             #ident: self.#ident.clone()
        //         })
        //     }
        //     None => {
        //         // 添加判断条件
        //         condition_token_vec.push(quote! {
        //             if self.#ident.is_none(){
        //                 let err = format!("{} field missing", stringify!(#ident));
        //                 return std::result::Result::Err(err.into());
        //             }
        //         });
        //         // 添加new字段，不是option字段，那我们返回Option的值
        //         new_token_vec.push(quote! {
        //             #ident: self.#ident.clone().unwrap()
        //         })
        //     }
        // }
    }

    let token = quote! {
        fn build(&mut self) -> std::result::Result<#struct_ident,std::boxed::Box<dyn std::error::Error>>{
            #(#condition_token_vec)*

            std::result::Result::Ok(#struct_ident {
                #(#new_token_vec),*
            })

        }
    };
    Ok(token)
}

fn impl_builder(st: &syn::DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
    let name_ident = &st.ident;
    let builder_name_ident = syn::Ident::new(
        &format!("{}Builder", name_ident.to_string()),
        st.ident.span(),
    );
    let origin_struct_fields = get_struct_fields(st)?;
    // let idents = origin_struct_fields
    //     .iter()
    //     .map(|field| &field.ident)
    //     .collect::<Vec<_>>();
    let builder = generate_builder_function(&origin_struct_fields)?;
    let builder_field = generate_builder_struct_field(&origin_struct_fields)?;
    let builder_setter_function = generate_builder_setter_function(&origin_struct_fields)?;
    let builder_build_function =
        generate_builder_build_function(&name_ident, &origin_struct_fields)?;
    let generated = quote! {

        pub struct #builder_name_ident{
            #(#builder_field), *
        }

        impl #name_ident {
            pub fn builder() -> #builder_name_ident{
                #builder_name_ident {
                     // #(#idents: std::option::Option::None),*
                    #(#builder),*
                }
            }
        }

        impl #builder_name_ident {
            #builder_build_function
            #builder_setter_function
        }

    };
    Ok(generated)
}

#[proc_macro_derive(OptionDemo)]
pub fn option_demo(input: TokenStream) -> TokenStream {
    let st = syn::parse_macro_input!(input as syn::DeriveInput);

    eprintln!("data:{:#?}", st.data);

    let fields = get_struct_fields(&st).unwrap();

    println!("--------{:#?}", fields);

    let inner_type = get_optional_field_inner_type(fields.first().unwrap()).unwrap();
    println!("inner_type: {:#?}", inner_type);

    proc_macro2::TokenStream::new().into()
}

#[proc_macro_derive(AttributeDemo)]
pub fn attr_demo(input: TokenStream) -> TokenStream {
    let st = syn::parse_macro_input!(input as syn::DeriveInput);
    // for attr in &st.attrs{
    //     eprintln!("attrs:{:#?}", attr);
    //     eprintln!("attr.path:{:#?}",attr.path().is_ident("Foo"));
    // }

    let attr = st.attrs.first().unwrap();

    eprintln!("attr:{:#?}", attr);

    // if let syn::Meta::List(list) = &attr.meta{
    //     let content;
    //     parenthesized!(content in list.tokens);
    //
    // }
    //
    //
    attr.parse_nested_meta(|meta| {
        let content;
        parenthesized!(content in meta.input);
        let lit = content.parse::<syn::LitInt>().unwrap();
        eprintln!("content:{:#?}", lit);
        // eprintln!("meta_path:{:#?}",meta.path);
        // eprintln!("meta_value:{:#?}",meta.input);
        Ok(())
    })
    .unwrap();

    let mm: syn::Expr = attr.parse_args().unwrap();
    eprintln!("mm:{:#?}", mm);

    TokenStream::new()
}
